﻿using ShenGu.Script;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ScriptTest
{
    public partial class ScriptBuildForm : Form
    {
        public ScriptBuildForm(string script)
        {
            InitializeComponent();
            if (!string.IsNullOrEmpty(script)) txtContent.Text = script;
        }

        private DataTable CreateUserTable()
        {
            DataTable table = new DataTable("Users");
            table.Columns.Add("UserId", typeof(string));
            table.Columns.Add("UserName", typeof(string));
            table.Columns.Add("Age", typeof(int));
            table.Rows.Add("Admin", "管理员", 25);
            table.Rows.Add("Tester", "测试人员", 24);
            return table;
        }

        private void btnBuild_Click(object sender, EventArgs e)
        {
            try
            {
                string text = txtContent.Text;

                //将包含<@XXX></@XXX>的标签，转成可以执行的javascript语法
                TagParser reader = new TagParser();
                ScriptBuilder builder = new ScriptBuilder();
                string script = reader.Parse(text, true);

                //解析javascript语法
                ScriptParser parser = ScriptParser.Parse(script);

                //创建脚本上下文
                ScriptContext context = new ScriptContext();
                context.AddValue("users", CreateUserTable());
                context.AddValue("status", 3);

                //执行javascript脚本
                ScriptExecutor executor = new ScriptExecutor(text);
                reader.Execute(parser, context, executor);

                //读取结果
                string content = executor.ToString();

                using (ScriptBuildResultForm form = new ScriptBuildResultForm(script, content))
                    form.ShowDialog();
            }
            catch(Exception ex)
            {
                MessageBox.Show("出现异常：" + ex.Message);
            }
        }

        private IScriptComponent CreateExecutor(ScriptContext context, string path)
        {
            string content = Utils.GetBuildContent(path);
            ScriptBuilder builder = new ScriptBuilder();
            TagParser reader = new TagParser();
            reader.Parse(builder, content, true);

            return new PageComponent((StringBuilder)context.GetCacheValue("Builder"), content, builder.BodyScript, builder.ArgusScript);
        }
    }

    class ScriptResult
    {
        private string source;
        private StringBuilder builder;

        public ScriptResult(string source)
        {
            this.source = source;
            this.builder = new StringBuilder();
        }

        [ScriptMapping("output")]
        public void Output(int index, int length)
        {
            builder.Append(source.Substring(index, length));
        }

        [ScriptMapping("write")]
        public void Write(IScriptObject value, ScriptContext context)
        {
            builder.Append(value.ToValueString(context));
        }

        public override string ToString()
        {
            return builder.ToString();
        }
    }

    class ScriptBuilder : IScriptBuilder
    {
        private StringBuilder sb = new StringBuilder();

        public string ArgusScript { get; set; }

        public string BodyScript
        {
            get { return sb.ToString(); }
        }

        public void AppendBodyScript(string script)
        {
            sb.Append(script);
        }

        public void CheckComponent(string path)
        {
        }
    }

    class ScriptExecutor : IScriptExecutor
    {
        private StringBuilder sb;
        private string source;

        public ScriptExecutor(string source)
        {
            this.sb = new StringBuilder();
            this.source = source;
        }

        public void Output(ScriptContext context, int index, int length)
        {
            sb.Append(source, index, length);
        }

        public void Write(ScriptContext context, IScriptObject value)
        {
            sb.Append(value.ToValueString(context));
        }

        public IScriptComponent GetComponent(ScriptContext context, string path)
        {
            string content = Utils.GetBuildContent(path);
            ScriptBuilder builder = new ScriptBuilder();
            TagParser reader = new TagParser();
            reader.Parse(builder, content, true);

            return new PageComponent(sb, content, builder.BodyScript, builder.ArgusScript);
        }

        public override string ToString()
        {
            return sb.ToString();
        }
    }

    class PageComponent : IScriptComponent
    {
        private string source;
        private string bodyScript;
        private string argusScript;
        private StringBuilder builder;

        public PageComponent(StringBuilder builder, string source, string bodyScript, string argusScript )
        {
            this.bodyScript = bodyScript;
            this.argusScript = argusScript;
            this.builder = builder;
            this.source = source;
        }

        public string ArgusScript { get { return argusScript; } }

        public string BodyScript { get { return bodyScript; } }

        public void Output(ScriptContext context, int index, int length)
        {
            builder.Append(source, index, length);
        }

        public void Write(ScriptContext context, IScriptObject value)
        {
            builder.Append(value.ToValueString(context));
        }

        public override string ToString()
        {
            return builder.ToString();
        }

        public void CheckArgus(ScriptContext context, ScriptObject thisObject)
        {
        }
    }
}
